home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d11 / frasrc14.arc / ZOOM.C < prev   
C/C++ Source or Header  |  1990-08-02  |  17KB  |  472 lines

  1. /*
  2.     zoom.c - routines for zoombox manipulation and for panning
  3.  
  4. */
  5.  
  6. #include <float.h>
  7. #include "fractint.h"
  8.  
  9. /* screen dimensions here are (1.0,0.75) corresponding to (xdots-1,ydots-1) */
  10. extern double zbx,zby;           /* topleft of unrotated zoombox  */
  11. extern double zwidth,zdepth,zskew; /* zoombox size & shape        */
  12. extern int zrotate;           /* * 2.5 degree increments        */
  13. extern int boxcount,boxx[],boxy[]; /* co-ords of each zoombox pixel */
  14. extern int xdots,ydots;
  15. extern double dxsize,dysize;       /* xdots-1, ydots-1            */
  16. extern double xxmin,yymin,xxmax,yymax,xx3rd,yy3rd;
  17. extern double sxmin,symin,sxmax,symax,sx3rd,sy3rd;
  18. /* top      left    corner of screen is (xxmin,yymax) */
  19. /* bottom left    corner of screen is (xx3rd,yy3rd) */
  20. /* bottom right corner of screen is (xxmax,yymin) */
  21. extern double plotmx1,plotmx2,plotmy1,plotmy2;
  22.  
  23. extern int  calc_status;       /* status of calculations */
  24. extern int  fractype;           /* fractal type */
  25. extern int  numpasses;           /* 0 = 1 pass, 1 = double pass */
  26. extern int  solidguessing;       /* 1 if solid-guessing */
  27. extern int  boundarytraceflag;       /* 1 if boundary tracing */
  28. extern int  num_worklist;       /* resume worklist for standard engine */
  29. extern struct workliststuff worklist[MAXCALCWORK];
  30. extern char dstack[4096];       /* common temp, used for get_line/put_line */
  31. extern int  StandardFractal();
  32. extern int  calcmand();
  33. extern char potfile[];           /* potential filename */
  34.  
  35. struct coords {
  36.     int x,y;
  37.     };
  38.  
  39. #define ASPECTRATIO 1.33333333333333
  40. #define PIXELROUND 0.00001
  41.  
  42. static void drawlines(struct coords, struct coords, int, int);
  43. static void addbox(struct coords);
  44. static void zmo_calc(double, double, double *, double *);
  45. static int  check_pan();
  46. static void fix_worklist();
  47.  
  48. void drawbox(int drawit)
  49. {   struct coords tl,bl,tr,br; /* dot addr of topleft, botleft, etc */
  50.     double tmpx,tmpy,dx,dy,rotcos,rotsin,ftemp1,ftemp2;
  51.     double fxwidth,fxskew,fydepth,fyskew,fxadj;
  52.  
  53.     if (zwidth==0) { /* no box to draw */
  54.     if (boxcount!=0) { /* remove the old box from display */
  55.         clearbox();   /* asm routine */
  56.         boxcount = 0; }
  57.     xxmin = sxmin;      /* set corners to full screen and return */
  58.     xxmax = sxmax;
  59.     xx3rd = sx3rd;
  60.     yymin = symin;
  61.     yymax = symax;
  62.     yy3rd = sy3rd;
  63.     return; }
  64.  
  65.     ftemp1 = PI*zrotate/72; /* convert to radians */
  66.     rotcos = cos(ftemp1);   /* sin & cos of rotation */
  67.     rotsin = sin(ftemp1);
  68.  
  69.     /* do some calcs just once here to reduce fp work a bit */
  70.     fxwidth = sxmax-sx3rd;
  71.     fxskew  = sx3rd-sxmin;
  72.     fydepth = sy3rd-symax;
  73.     fyskew  = symin-sy3rd;
  74.     fxadj   = zwidth*zskew;
  75.  
  76.     /* calc co-ords of topleft & botright corners of box */
  77.     tmpx = zwidth/-2+fxadj; /* x/y co-ords from center of zoombox as origin */
  78.     tmpy = zdepth/2;        /* using screen dimensions (1,.75) as the scale */
  79.     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx; /* delta x to rotate topleft */
  80.     dy = tmpy - (rotsin*tmpx + rotcos*tmpy); /* delta y to rotate topleft */
  81.     /* calc co-ords of topleft */
  82.     ftemp1 = zbx+dx+fxadj;
  83.     ftemp2 = (zby+dy)*ASPECTRATIO;
  84.     tl.x   = ftemp1*(dxsize+PIXELROUND); /* screen co-ords */
  85.     tl.y   = ftemp2*(dysize+PIXELROUND);
  86.     xxmin  = sxmin + ftemp1*fxwidth + ftemp2*fxskew; /* real co-ords */
  87.     yymax  = symax + ftemp2*fydepth + ftemp1*fyskew;
  88.     /* calc co-ords of bottom right */
  89.     ftemp1 = zbx+zwidth-dx-fxadj;
  90.     ftemp2 = (zby+zdepth-dy)*ASPECTRATIO;
  91.     br.x   = ftemp1*(dxsize+PIXELROUND);
  92.     br.y   = ftemp2*(dysize+PIXELROUND);
  93.     xxmax  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  94.     yymin  = symax + ftemp2*fydepth + ftemp1*fyskew;
  95.  
  96.     /* do the same for botleft & topright */
  97.     tmpx = zwidth/-2-fxadj;
  98.     tmpy = 0.0-tmpy;
  99.     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx;
  100.     dy = tmpy - (rotsin*tmpx + rotcos*tmpy);
  101.     ftemp1 = zbx+dx-fxadj;
  102.     ftemp2 = (zby+dy+zdepth)*ASPECTRATIO;
  103.     bl.x   = ftemp1*(dxsize+PIXELROUND);
  104.     bl.y   = ftemp2*(dysize+PIXELROUND);
  105.     xx3rd  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  106.     yy3rd  = symax + ftemp2*fydepth + ftemp1*fyskew;
  107.     ftemp1 = zbx+zwidth-dx+fxadj;
  108.     ftemp2 = (zby-dy)*ASPECTRATIO;
  109.     tr.x   = ftemp1*(dxsize+PIXELROUND);
  110.     tr.y   = ftemp2*(dysize+PIXELROUND);
  111.  
  112.     if (boxcount!=0) { /* remove the old box from display */
  113.     clearbox();   /* asm routine */
  114.     boxcount = 0; }
  115.  
  116.     if (drawit) { /* caller wants box drawn as well as co-ords calc'd */
  117.     /* build the list of zoom box pixels */
  118.     addbox(tl); addbox(tr);           /* corner pixels */
  119.     addbox(bl); addbox(br);
  120.     drawlines(tl,tr,bl.x-tl.x,bl.y-tl.y); /* top & bottom lines */
  121.     drawlines(tl,bl,tr.x-tl.x,tr.y-tl.y); /* left & right lines */
  122.     dispbox();                  /* asm routine to paint it */
  123.     }
  124.     }
  125.  
  126. static void drawlines(struct coords fr, struct coords to, int dx, int dy)
  127. {   int xincr,yincr,ctr;
  128.     int altctr,altdec,altinc;
  129.     struct coords tmpp,line1,line2;
  130.  
  131.     if (abs(to.x-fr.x) > abs(to.y-fr.y)) { /* delta.x > delta.y */
  132.     if (fr.x>to.x) { /* swap so from.x is < to.x */
  133.         tmpp = fr; fr = to; to = tmpp; }
  134.     xincr = (to.x-fr.x)*4/xdots+1; /* do every 1st, 2nd, 3rd, or 4th dot */
  135.     ctr = (to.x-fr.x-1)/xincr;
  136.     altdec = abs(to.y-fr.y)*xincr;
  137.     altinc = to.x-fr.x;
  138.     altctr = altinc/2;
  139.     yincr = (to.y>fr.y)?1:-1;
  140.     line2.x = (line1.x = fr.x) + dx;
  141.     line2.y = (line1.y = fr.y) + dy;
  142.     while (--ctr>=0) {
  143.         line1.x += xincr;
  144.         line2.x += xincr;
  145.         altctr -= altdec;
  146.         while (altctr<0) {
  147.         altctr    += altinc;
  148.         line1.y += yincr;
  149.         line2.y += yincr;
  150.         }
  151.         addbox(line1);
  152.         addbox(line2);
  153.         }
  154.     }
  155.  
  156.     else { /* delta.y > delta.x */
  157.     if (fr.y>to.y) { /* swap so from.y is < to.y */
  158.         tmpp = fr; fr = to; to = tmpp; }
  159.     yincr = (to.y-fr.y)*4/ydots+1; /* do every 1st, 2nd, 3rd, or 4th dot */
  160.     ctr = (to.y-fr.y-1)/yincr;
  161.     altdec = abs(to.x-fr.x)*yincr;
  162.     altinc = to.y-fr.y;
  163.     altctr = altinc/2;
  164.     xincr = (to.x>fr.x) ? 1 : -1;
  165.     line2.x = (line1.x = fr.x) + dx;
  166.     line2.y = (line1.y = fr.y) + dy;
  167.     while (--ctr>=0) {
  168.         line1.y += yincr;
  169.         line2.y += yincr;
  170.         altctr  -= altdec;
  171.         while (altctr<0) {
  172.         altctr    += altinc;
  173.         line1.x += xincr;
  174.         line2.x += xincr;
  175.         }
  176.         addbox(line1);
  177.         addbox(line2);
  178.         }
  179.     }
  180.     }
  181.  
  182. static void addbox(struct coords point)
  183. {   if (point.x>=0 && point.x<xdots && point.y>=0 && point.y<ydots) {
  184.     boxx[boxcount] = point.x;
  185.     boxy[boxcount] = point.y;
  186.     ++boxcount;
  187.     }
  188.     }
  189.  
  190. void moveboxf(double dx, double dy)
  191. {   int align,row,col;
  192.     align = check_pan();
  193.     if (dx!=0.0) {
  194.     if ((zbx+=dx)+zwidth/2<0)  /* center must stay onscreen */
  195.         zbx = zwidth/-2;
  196.     if (zbx+zwidth/2>1)
  197.         zbx = 1.0-zwidth/2;
  198.     if (align != 0
  199.       && ((col = zbx*(dxsize+PIXELROUND)) & (align-1)) != 0) {
  200.         if (dx > 0) col += align;
  201.         col -= col & (align-1); /* adjust col to pass alignment */
  202.         zbx = (double)col/dxsize; }
  203.     }
  204.     if (dy!=0.0) {
  205.     if ((zby+=dy)+zdepth/2<0)
  206.         zby = zdepth/-2;
  207.     if (zby+zdepth/2>0.75)
  208.         zby = 0.75-zdepth/2;
  209.     if (align != 0
  210.       && ((row = zby*ASPECTRATIO*(dysize+PIXELROUND)) & (align-1)) != 0) {
  211.         if (dy > 0) row += align;
  212.         row -= row & (align-1);
  213.         zby = (double)row/dysize/ASPECTRATIO; }
  214.     }
  215.     }
  216.  
  217. void chgboxf(double dwidth, double ddepth)
  218. {
  219.     if (zwidth+dwidth>1)
  220.     dwidth = 1.0-zwidth;
  221.     if (zwidth+dwidth<0.05)
  222.     dwidth = 0.05-zwidth;
  223.     zwidth += dwidth;
  224.     if (zdepth+ddepth>0.75)
  225.     ddepth = 0.75-zdepth;
  226.     if (zdepth+ddepth<0.0375)
  227.     ddepth = 0.0375-zdepth;
  228.     zdepth += ddepth;
  229.     moveboxf(dwidth/-2,ddepth/-2); /* keep it centered & check limits */
  230.     }
  231.  
  232. void chgboxi(int dw, int dd)
  233. {   /* change position/size by pixels */
  234.     chgboxf( (double)dw/dxsize, (double)dd*0.75/dysize );
  235.     }
  236.  
  237. zoomout() /* for ctl-enter, calc corners for zooming out */
  238. {   double savxxmin,savyymax,ftemp;
  239.     /* (xxmin,yymax), etc, are already set to zoombox corners;
  240.        (sxmin,symax), etc, are still the screen's corners;
  241.        use the same logic as plot_orbit stuff to first calculate current screen
  242.        corners relative to the zoombox, as if the zoombox were a square with
  243.        upper left (0,0) and width/depth 1; ie calc the current screen corners
  244.        as if plotting them from the zoombox;
  245.        then extend these co-ords from current real screen corners to get
  246.        new actual corners
  247.        */
  248.     ftemp = (yymin-yy3rd)*(xx3rd-xxmin) - (xxmax-xx3rd)*(yy3rd-yymax);
  249.     plotmx1 = (xx3rd-xxmin) / ftemp; /* reuse the plotxxx vars is safe */
  250.     plotmx2 = (yy3rd-yymax) / ftemp;
  251.     plotmy1 = (yymin-yy3rd) / ftemp;
  252.     plotmy2 = (xxmax-xx3rd) / ftemp;
  253.     savxxmin = xxmin; savyymax = yymax;
  254.     zmo_calc(sxmin-savxxmin,symax-savyymax,&xxmin,&yymax); /* new xxmin/xxmax */
  255.     zmo_calc(sxmax-savxxmin,symin-savyymax,&xxmax,&yymin);
  256.     zmo_calc(sx3rd-savxxmin,sy3rd-savyymax,&xx3rd,&yy3rd);
  257.     }
  258.  
  259. static void zmo_calc(double dx, double dy, double *newx, double *newy)
  260. {   double tempx,tempy;
  261.     /* calc cur screen corner relative to zoombox, when zoombox co-ords
  262.        are taken as (0,0) topleft thru (1,1) bottom right */
  263.     tempx = dy * plotmx1 - dx * plotmx2;
  264.     tempy = dx * plotmy1 - dy * plotmy2;
  265.     /* calc new corner by extending from current screen corners */
  266.     *newx = sxmin + tempx*(sxmax-sx3rd) + tempy*(sx3rd-sxmin);
  267.     *newy = symax + tempy*(sy3rd-symax) + tempx*(symin-sy3rd);
  268.     }
  269.  
  270. static int check_pan() /* return 0 if can't, alignment requirement if can */
  271. {   int i,j;
  272.     if (calc_status != 2 && calc_status != 4)
  273.     return(0); /* not resumable, not complete */
  274.     if ( fractalspecific[fractype].calctype != StandardFractal
  275.       && fractalspecific[fractype].calctype != calcmand)
  276.     return(0); /* not a worklist-driven type */
  277.     if (zwidth != 1.0 || zdepth != 0.75 || zskew != 0.0 || zrotate != 0.0)
  278.     return(0); /* not a full size unrotated unskewed zoombox */
  279.     /* can pan if we get this far */
  280.     if (calc_status == 4)
  281.     return(1); /* image completed, align on any pixel */
  282.     if (boundarytraceflag && (fractalspecific[fractype].flags&NOTRACE) == 0
  283.       && potfile[0] == 0)
  284.     return(1); /* btm, align on any pixel */
  285.     if (solidguessing == 0 || (fractalspecific[fractype].flags&NOGUESS))
  286.     return(numpasses+1); /* align on any pixel for 1pass, even for 2pass */
  287.     /* solid guessing */
  288.     start_resume();
  289.     get_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  290.     /* don't do end_resume! we're just looking */
  291.     i = 9;
  292.     for (j=0; j<num_worklist; ++j) /* find lowest pass in any pending window */
  293.     if (worklist[j].pass < i)
  294.         i = worklist[j].pass;
  295.     j = ssg_blocksize(); /* worst-case alignment requirement */
  296.     while (--i >= 0)
  297.     j = j>>1; /* reduce requirement */
  298.     return(j);
  299.     }
  300.  
  301. static void move_row(fromrow,torow,col) /* move a row on the screen */
  302. {   int startcol,endcol,tocol;
  303.     memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */
  304.     if (fromrow >= 0 && fromrow < ydots) {
  305.     tocol = startcol = 0;
  306.     endcol = xdots-1;
  307.     if (col < 0) {
  308.         tocol -= col;
  309.         endcol += col; }
  310.     if (col > 0)
  311.         startcol += col;
  312.     get_line(fromrow,startcol,endcol,&dstack[tocol]);
  313.     }
  314.     put_line(torow,0,xdots-1,dstack);
  315.     }
  316.  
  317. init_pan_or_recalc(zoomout) /* decide to recalc, or to chg worklist & pan */
  318. {   int i,j,row,col,y,alignmask,direction,listfull;
  319.     if (zwidth == 0.0)
  320.     return(0); /* no zoombox, leave calc_status as is */
  321.     /* got a zoombox */
  322.     if ((alignmask=check_pan()-1) < 0) {
  323.     calc_status = 0; /* can't pan, trigger recalc */
  324.     return(0); }
  325.     if (zbx == 0.0 && zby == 0.0) {
  326.     clearbox();
  327.     return(0); } /* box is full screen, leave calc_status as is */
  328.     col = zbx*(dxsize+PIXELROUND); /* calc dest col,row of topleft pixel */
  329.     row = zby*ASPECTRATIO*(dysize+PIXELROUND);
  330.     if (zoomout) { /* invert row and col */
  331.     row = 0-row;
  332.     col = 0-col; }
  333.     if ((row&alignmask) != 0 || (col&alignmask) != 0) {
  334.     calc_status = 0; /* not on useable pixel alignment, trigger recalc */
  335.     return(0); }
  336.     /* pan */
  337.     num_worklist = 0;
  338.     if (calc_status == 2) {
  339.        start_resume();
  340.        get_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  341.        } /* don't do end_resume! we might still change our mind */
  342.     /* adjust existing worklist entries */
  343.     for (i=0; i<num_worklist; ++i) {
  344.     worklist[i].yystart -= row;
  345.     worklist[i].yystop  -= row;
  346.     worklist[i].yybegin -= row;
  347.     worklist[i].xxstart -= col;
  348.     worklist[i].xxstop  -= col;
  349.     }
  350.     /* add worklist entries for the new edges */
  351.     listfull = i = 0;
  352.     j = ydots-1;
  353.     if (row < 0) {
  354.     listfull |= add_worklist(0,xdots-1,0,0-row-1,0,0,0);
  355.     i = 0 - row; }
  356.     if (row > 0) {
  357.     listfull |= add_worklist(0,xdots-1,ydots-row,ydots-1,ydots-row,0,0);
  358.     j = ydots - row - 1; }
  359.     if (col < 0)
  360.     listfull |= add_worklist(0,0-col-1,i,j,i,0,0);
  361.     if (col > 0)
  362.     listfull |= add_worklist(xdots-col,xdots-1,i,j,i,0,0);
  363.     if (listfull != 0) {
  364.     setfortext();
  365.     printf("\n\n\nTables full, can't pan current image.");
  366.     printf("\n\nEscape to resume old image, any other key to calc new one.\n");
  367.     i = getakey();
  368.     setforgraphics();
  369.     if (i == 27) { /* escape */
  370.         zwidth = 0; /* cancel the zoombox */
  371.         drawbox(1); }
  372.     else
  373.         calc_status = 0; /* trigger recalc */
  374.     return(0); }
  375.     /* now we're committed */
  376.     calc_status = 2;
  377.     clearbox();
  378.     if (row > 0) /* move image up */
  379.     for (y=0; y<ydots; ++y) move_row(y+row,y,col);
  380.     else     /* move image down */
  381.     for (y=ydots; --y>=0;)    move_row(y+row,y,col);
  382.     fix_worklist(); /* fixup any out of bounds worklist entries */
  383.     alloc_resume(sizeof(worklist)+10,1); /* post the new worklist */
  384.     put_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  385.     }
  386.  
  387. static void restart_window(int wknum) /* force a worklist entry to restart */
  388. {   int i,yfrom,yto,xfrom,xto;
  389.     if ((yfrom = worklist[wknum].yystart) < 0) yfrom = 0;
  390.     if ((xfrom = worklist[wknum].xxstart) < 0) xfrom = 0;
  391.     if ((yto = worklist[wknum].yystop) >= ydots) yto = ydots - 1;
  392.     if ((xto = worklist[wknum].xxstop) >= xdots) xto = xdots - 1;
  393.     memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */
  394.     while (yfrom <= yto)
  395.     put_line(yfrom++,xfrom,xto,dstack);
  396.     worklist[wknum].sym = worklist[wknum].pass = 0;
  397.     worklist[wknum].yybegin = worklist[wknum].yystart;
  398. }
  399.  
  400. static void fix_worklist() /* fix out of bounds and symmetry related stuff */
  401. {   int i,j,k;
  402.     struct workliststuff *wk;
  403.     for (i=0; i<num_worklist; ++i) {
  404.     wk = &worklist[i];
  405.     if ( wk->yystart >= ydots || wk->yystop < 0
  406.       || wk->xxstart >= xdots || wk->xxstop < 0) { /* offscreen, delete */
  407.         for (j=i+1; j<num_worklist; ++j)
  408.         worklist[j-1] = worklist[j];
  409.         --num_worklist;
  410.         --i;
  411.         continue; }
  412.     if (wk->yystart < 0) /* partly off top edge */
  413.         if ((wk->sym&1) == 0) /* no sym, easy */
  414.         wk->yystart = 0;
  415.         else { /* xaxis symmetry */
  416.         if ((j = wk->yystop + wk->yystart) > 0
  417.           && num_worklist < MAXCALCWORK) { /* split the sym part */
  418.             worklist[num_worklist] = worklist[i];
  419.             worklist[num_worklist].yystart = 0;
  420.             worklist[num_worklist++].yystop = j;
  421.             wk->yystart = j+1; }
  422.         else
  423.             wk->yystart = 0;
  424.         restart_window(i); /* restart the no-longer sym part */
  425.         }
  426.     if (wk->yystop >= ydots) { /* partly off bottom edge */
  427.        j = ydots-1;
  428.        if ((wk->sym&1) != 0) { /* uses xaxis symmetry */
  429.           if ((k = wk->yystart + (wk->yystop - j)) < j)
  430.          if (num_worklist >= MAXCALCWORK) /* no room to split */
  431.             restart_window(i);
  432.          else { /* split it */
  433.             worklist[num_worklist] = worklist[i];
  434.             worklist[num_worklist].yystart = k;
  435.             worklist[num_worklist++].yystop = j;
  436.             j = k-1; }
  437.           wk->sym &= -1 - 1; }
  438.        wk->yystop = j; }
  439.     if (wk->xxstart < 0) /* partly off left edge */
  440.         if ((wk->sym&2) == 0) /* no sym, easy */
  441.         wk->xxstart = 0;
  442.         else { /* yaxis symmetry */
  443.         if ((j = wk->xxstop + wk->xxstart) > 0
  444.           && num_worklist < MAXCALCWORK) { /* split the sym part */
  445.             worklist[num_worklist] = worklist[i];
  446.             worklist[num_worklist].xxstart = 0;
  447.             worklist[num_worklist++].xxstop = j;
  448.             wk->xxstart = j+1; }
  449.         else
  450.             wk->xxstart = 0;
  451.         restart_window(i); /* restart the no-longer sym part */
  452.         }
  453.     if (wk->xxstop >= xdots) { /* partly off right edge */
  454.        j = xdots-1;
  455.        if ((wk->sym&2) != 0) { /* uses xaxis symmetry */
  456.           if ((k = wk->xxstart + (wk->xxstop - j)) < j)
  457.          if (num_worklist >= MAXCALCWORK) /* no room to split */
  458.             restart_window(i);
  459.          else { /* split it */
  460.             worklist[num_worklist] = worklist[i];
  461.             worklist[num_worklist].xxstart = k;
  462.             worklist[num_worklist++].xxstop = j;
  463.             j = k-1; }
  464.           wk->sym &= -1 - 2; }
  465.        wk->xxstop = j; }
  466.     if (wk->yybegin < wk->yystart) wk->yybegin = wk->yystart;
  467.     if (wk->yybegin > wk->yystop)  wk->yybegin = wk->yystop;
  468.     }
  469.     tidy_worklist(); /* combine where possible, re-sort */
  470. }
  471.  
  472.